package com.fgbf.todo.Managers;

import java.util.ArrayList;

import android.app.Activity;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.util.Log;

import com.fgbf.todo.Data.DB.DBHelper;
import com.fgbf.todo.Data.SharedData.SharedData;
import com.fgbf.todo.MainClasses.Category;
import com.fgbf.todo.MainClasses.Task;
import com.fgbf.todo.MainClasses.User;

/**
 * Task Manager
 * @author Warren Shenk
 * @date 3/5/2012
 */
public class TaskManager {
	
	/////////////////////////////////////////////////////////////////////////
	// INSTANCE DATA
	/////////////////////////////////////////////////////////////////////////
	/**
	 * The Current User
	 */
	private User currUser;
	/**
	 * The Current Context 
	 */
	private Context context;
	/**
	 * The database helper
	 */
	private DBHelper dbHelper;
	/**
	 * The database
	 */
	private SQLiteDatabase database;
	/**
	 * LoginManager
	 */
	private LoginManager lgMgr;
	
	
	/////////////////////////////////////////////////////////////////////////
	// CONSTRUCTOR
	/////////////////////////////////////////////////////////////////////////
	
	/**
	 * Constructor, takes in the current user
	 * @param user The current user
	 */
	public TaskManager(Context context, User user){
		this.context = context;
		this.currUser = user;
	}
	//----------------------------------------------------------------------
	
	/**
	 * Constructor takes in the current activity
	 * @param context The current context
	 */
	public TaskManager(Activity act) {
		this.context = act.getApplicationContext();
		this.lgMgr = new LoginManager(this.context);
		this.currUser = new User(lgMgr.getLoggedInUsername(act));
	}
	//----------------------------------------------------------------------

	
	/////////////////////////////////////////////////////////////////////////////////////////
	// PUBLIC METHODS
	/////////////////////////////////////////////////////////////////////////////////////////
	
	/**
	 * Updates the task's completion inside the database
	 * @param name The name of the desired task to update
	 * @param isCompleted Boolean value representing whether or not the task is completed, true if completed, false otherwise
	 */
	public void updateTaskCompletionInDB (String name, boolean isCompleted) {
		try{
			this.openDB();
			//editEntry here
			this.updateEntry(name, isCompleted);
			this.closeDB();
		}
		catch (Exception e){
			e.printStackTrace();
		}
		
	}
	//--------------------------------------------------------------------------------------

	
	/**
	 * Adds a user to the database
	 * @param task An instantiated task
	 * @return A boolean representing whether or not the user was added successfully
	 */
	public boolean addTaskToDB(Task task) {
		boolean taskAdded = true;
		try{
			this.openDB();
			createEntry(currUser.getUsername(), task.getName(), task.getNote(), 
					task.getPriority(), task.getCategory(), task.getDueDate(), task.getAddrStreet(),
					task.getAddrCity(), task.getAddrState(), task.getAddrZip());
			this.closeDB();
		}
		catch (Exception e) {
			taskAdded = false;
			e.printStackTrace();
		}
		return taskAdded;
	}
	//--------------------------------------------------------------------------------------
	
	/**
	 * Returns the Tasks from the Database
	 * @return An ArrayList of Tasks 
	 */
	public ArrayList<Task> getTasksFromDB() {	
		this.openDB();
		ArrayList<Task> temp = getTaskArrayList();
		this.closeDB();
		return temp;
	}
	//--------------------------------------------------------------------------------------
	
	/**
	 * Returns the filtered Tasks from the Database
	 * @return An ArrayList of filtered tasks
	 */
	public ArrayList<Task> getFilteredTasksFromDB(boolean filterByCategory, Category cat, 
													boolean filterOutCompleted, boolean filterByDate, long date) {
		ArrayList<Task> temp = new ArrayList<Task>();
 		try {
			this.openDB();
			temp = this.getFilteredTaskArrayList(filterByCategory, cat, filterOutCompleted,
																				filterByDate, date);
			this.closeDB();
		}
		catch(Exception e) {
			Log.v("EXCEPTION", e.getMessage());
		}
		return temp;
	}
	//--------------------------------------------------------------------------------------

	
	/**
	 * Returns a specific Task from the Database
	 * @param taskName The name of the desired task
	 * @return The desired task
	 */
	public Task getTaskFromDB(String taskName) {
		this.openDB();
		Task temp = getTask(taskName);
		this.closeDB();
		return temp;
	}
	//--------------------------------------------------------------------------------------


	/**
	 * Prints out the values in the database into logcat
	 */
	public void dumpTaskDB() {
		this.openDB();
		String str = this.getData();
		this.closeDB();
		Log.v("TABLE", "" + str);
	}
	//--------------------------------------------------------------------------------------
	
	/**
	 * Updates the "task to be viewed" in shared data
	 */
	public void updateTaskToBeViewed(String taskName, Activity act) {
		SharedData.putString(act, SharedData.KEY_TASK_TO_BE_VIEWED, taskName);
	}
	//---------------------------------------------------------------------------------------
	
	/**
	 * Gets the "task to be viewed" from shared data
	 */
	public String getTaskToBeViewed(Activity act) {
		return SharedData.getString(act, SharedData.KEY_TASK_TO_BE_VIEWED);
	}
	//---------------------------------------------------------------------------------------
	
	/**
	 * Sets the "is task edited" boolean in shared data
	 */
	public void setIsTaskNew(Boolean isTaskEdited, Activity act) {
		SharedData.putBoolean(act, SharedData.KEY_IS_TASK_NEW, isTaskEdited);
	}
	//---------------------------------------------------------------------------------------
	
	/**
	 * Gets the boolean "is task edited" from shared data
	 */
	public Boolean getIsTaskNew(Activity act) {
		return SharedData.getBoolean(act, SharedData.KEY_IS_TASK_NEW);
	}
	//---------------------------------------------------------------------------------------
	
	
	
	/////////////////////////////////////////////////////////////////////////////////////////
	// PRIVATE METHODS
	/////////////////////////////////////////////////////////////////////////////////////////
	
	/**
	 * Uses the DBHelper to open the database
	 * @return The current instance of LoginManager
	 */
	private TaskManager openDB() {
		dbHelper = new DBHelper(context);
		database = dbHelper.getWritableDatabase();
		return this;
	}
	//--------------------------------------------------------------------------------------

	/**
	 * Uses the DBHelper to close the database
	 */
	private void closeDB() {
		dbHelper.close();
	}
	//--------------------------------------------------------------------------------------

	/**
	 * Creates an username/password entry in the database
	 * Must open the database prior to calling and close the database after calling
	 * @param userName The desired username to be entered in the database
	 * @param passWord The desire password to be entered in the database
	 * @param taskPrior The priority of the task [0,3]
	 * @param taskCat The category of the task
	 * @return The rowId of the newly entered rowa
	 */
	private long createEntry(String userName, String taskName, String taskNote, int taskPrior, 
			String taskCat, long taskDueDate, String taskStreet, String taskCity, String taskState,
			String taskZip) {
		ContentValues cv = new ContentValues();
		cv.put(DBHelper.KEY_USERNAME, userName);
		cv.put(DBHelper.KEY_TASKNAME, taskName);
		cv.put(DBHelper.KEY_TASKNOTE, taskNote);
		cv.put(DBHelper.KEY_TASKPRIOR, taskPrior);
		cv.put(DBHelper.KEY_TASKCAT, taskCat);
		cv.put(DBHelper.KEY_TASKCOMP, 0);
		cv.put(DBHelper.KEY_TASKDATE, taskDueDate);
		cv.put(DBHelper.KEY_TASKSTREET, taskStreet);
		cv.put(DBHelper.KEY_TASKCITY, taskCity);
		cv.put(DBHelper.KEY_TASKSTATE, taskState);
		cv.put(DBHelper.KEY_TASKZIP, taskZip);
		return database.insert(DBHelper.DB_TASK_TABLE, null, cv);
	}
	//--------------------------------------------------------------------------------------
	
	/**
	 * Updates the task completion for a given task name
	 * @param taskName The given task name
	 * @param isComplete boolean representing task completion, true if complete
	 * @return boolean representing whether or not the database was updated
	 */
	private boolean updateEntry(String taskName, boolean isComplete) {
		ContentValues cv = new ContentValues();
		if (isComplete)
			cv.put(DBHelper.KEY_TASKCOMP, (int)1);
		else 
			cv.put(DBHelper.KEY_TASKCOMP, (int)0);
		return database.update(DBHelper.DB_TASK_TABLE, cv, DBHelper.KEY_TASKNAME + "='" + taskName + "'", null) > 0;
	}
	//--------------------------------------------------------------------------------------

	
	/**
	 * Returns string of data
	 * Need to open/close database before/after calling
	 * @return A String representation of all the username and passwords in the database
	 */
	private String getData() {
		String[] cols = new String[]{DBHelper.KEY_ROWID, DBHelper.KEY_USERNAME, DBHelper.KEY_TASKNAME, DBHelper.KEY_TASKNOTE, DBHelper.KEY_TASKPRIOR};
		Cursor c = database.query(DBHelper.DB_TASK_TABLE, cols, null, null, null, null, null);
		
		String result = "";
		
		int iRow = c.getColumnIndex(DBHelper.KEY_ROWID);
		int iUserName = c.getColumnIndex(DBHelper.KEY_USERNAME);
		int iTaskName = c.getColumnIndex(DBHelper.KEY_TASKNAME);
		int iTaskNote = c.getColumnIndex(DBHelper.KEY_TASKNOTE);
		int iTaskPrior = c.getColumnIndex(DBHelper.KEY_TASKPRIOR);
		
		for (c.moveToFirst(); !c.isAfterLast(); c.moveToNext()) {
			result = result + c.getString(iRow) + " " 
							+ c.getString(iUserName) + " " 
							+ c.getString(iTaskName) + " " 
							+ c.getString(iTaskNote) + " "
							+ c.getString(iTaskPrior)+ "\n";
		}
		
		return result;
	}
	//--------------------------------------------------------------------------------------
	
	/**
	 * Returns an arraylist of tasks in the database
	 * @return an ArrayList of Tasks
	 */
	private ArrayList<Task> getTaskArrayList() {
		String[] cols = new String[]{DBHelper.KEY_USERNAME, DBHelper.KEY_TASKNAME, DBHelper.KEY_TASKNOTE, 
				DBHelper.KEY_TASKPRIOR, DBHelper.KEY_TASKCAT, DBHelper.KEY_TASKCOMP, DBHelper.KEY_TASKDATE};
		Cursor c = database.query(DBHelper.DB_TASK_TABLE, cols, null, null, null, null, null);
		
		ArrayList<Task> results = new ArrayList<Task> ();
		
		int iUserName = c.getColumnIndex(DBHelper.KEY_USERNAME);
		int iTaskName = c.getColumnIndex(DBHelper.KEY_TASKNAME);
		int iTaskNote = c.getColumnIndex(DBHelper.KEY_TASKNOTE);
		int iTaskPrior = c.getColumnIndex(DBHelper.KEY_TASKPRIOR);
		int iTaskCat = c.getColumnIndex(DBHelper.KEY_TASKCAT);
		int iTaskDueDate = c.getColumnIndex(DBHelper.KEY_TASKDATE);
		int iTaskCompletion = c.getColumnIndex(DBHelper.KEY_TASKCOMP);
		
		for (c.moveToFirst(); !c.isAfterLast(); c.moveToNext()) {
			if (c.getString(iUserName).equals(currUser.getUsername())) {
				String taskName = c.getString(iTaskName);
				String taskNote = c.getString(iTaskNote);
				int taskPrior = c.getInt(iTaskPrior);
				String taskCat = c.getString(iTaskCat);
				long taskDueDate = c.getLong(iTaskDueDate);
				boolean taskComplete = (c.getInt(iTaskCompletion) == 1);
			
				
				results.add(new Task(taskName, taskNote, new Category(taskCat), taskPrior, taskDueDate, taskComplete));
			}
		}
		
		return results;
		
	}
	//--------------------------------------------------------------------------------------
	
	/**
	 * Filters a task arraylist for the given parameters
	 * @param taskList
	 * @param filterByCategory A boolean value which declares whether or not to filter by category
	 * @param cat The category to filter by
	 * @param filterOutCompleted A boolean value which declares whether or not to filter out the completed items
	 * @param filterByDate A boolean value which declares whether or not to filter by date
	 * @param date The date to filter by, items due before the given date will be removed
	 * @return A filtered task arraylist
	 */
	private ArrayList<Task> getFilteredTaskArrayList(boolean filterByCategory, Category cat, boolean filterOutCompleted,
			boolean filterByDate, long date) {
		
		ArrayList<Task> tempList = this.getTaskArrayList();
		
		filterTaskArrayList(tempList, filterByCategory, cat, filterOutCompleted, filterByDate, date);
		
		return tempList;
	}
	//--------------------------------------------------------------------------------------
	
	/**
	 * Filters a task arraylist for the given parameters
	 * @param taskList
	 * @param filterByCategory A boolean value which declares whether or not to filter by category
	 * @param cat The category to filter by
	 * @param filterOutCompleted A boolean value which declares whether or not to filter out the completed items
	 * @param filterByDate A boolean value which declares whether or not to filter by date
	 * @param date The date to filter by, items due before the given date will be removed
	 * @return A filtered task arraylist
	 */
	private void filterTaskArrayList(ArrayList<Task> taskList, boolean filterByCategory, Category cat, 
										boolean filterOutCompleted, boolean filterByDate, long date) {
		
		boolean itemRemoved = false;
		if (filterByCategory || filterOutCompleted || filterByDate) {
			for (int i = 0; i < taskList.size(); i++) {
				itemRemoved = false;
				Task tempTask = taskList.get(i);
				
				if (filterByCategory) {
					//filter for category
					if (!tempTask.getCategory().equals(cat.getCurrentCategory().toString())) {
						taskList.remove(tempTask);
						i--;
						itemRemoved = true;
					}
				}
				
				if (!itemRemoved && filterOutCompleted) {
					//filter for completion
					if(tempTask.isCompleted()) {
						taskList.remove(tempTask);
						i--;
						itemRemoved = true;
					}
				}
				
				if (!itemRemoved && filterByDate) {
					//filter by date
					if (tempTask.getDueDate() < date) {
						taskList.remove(tempTask);
						i--;
					}
				}
			}
		}
			
	}
	//--------------------------------------------------------------------------------------

	
	/**
	 * Returns a task from the DB
	 * @return Returns a task
	 */
	private Task getTask(String taskname) {
		String[] cols = new String[]{DBHelper.KEY_USERNAME, DBHelper.KEY_TASKNAME, 
				DBHelper.KEY_TASKNOTE, DBHelper.KEY_TASKPRIOR, DBHelper.KEY_TASKCAT, 
				DBHelper.KEY_TASKCOMP, DBHelper.KEY_TASKDATE, DBHelper.KEY_TASKSTREET, 
				DBHelper.KEY_TASKCITY, DBHelper.KEY_TASKSTATE, DBHelper.KEY_TASKZIP};
		Cursor c = database.query(DBHelper.DB_TASK_TABLE, cols, null, null, null, null, null);
		
		Task tempTask = new Task("DNE");
		
		int iUserName = c.getColumnIndex(DBHelper.KEY_USERNAME);
		int iTaskName = c.getColumnIndex(DBHelper.KEY_TASKNAME);
		int iTaskNote = c.getColumnIndex(DBHelper.KEY_TASKNOTE);
		int iTaskPrior = c.getColumnIndex(DBHelper.KEY_TASKPRIOR);
		int iTaskCat = c.getColumnIndex(DBHelper.KEY_TASKCAT);
		int iTaskDueDate = c.getColumnIndex(DBHelper.KEY_TASKDATE);
		int iTaskCompletion = c.getColumnIndex(DBHelper.KEY_TASKCOMP);
		int iTaskStreet = c.getColumnIndex(DBHelper.KEY_TASKSTREET);
		int iTaskCity = c.getColumnIndex(DBHelper.KEY_TASKCITY);
		int iTaskState = c.getColumnIndex(DBHelper.KEY_TASKSTATE);
		int iTaskZip = c.getColumnIndex(DBHelper.KEY_TASKZIP);
		
		
		for (c.moveToFirst(); !c.isAfterLast(); c.moveToNext()) {
			if (c.getString(iUserName).equals(currUser.getUsername()) && c.getString(iTaskName).equals(taskname)){
			
			String taskName = c.getString(iTaskName);
			String taskNote = c.getString(iTaskNote);
			int taskPrior = c.getInt(iTaskPrior);
			String taskCat = c.getString(iTaskCat);
			long taskDueDate = c.getLong(iTaskDueDate);
			boolean taskComplete = (c.getInt(iTaskCompletion) == 1);
			String taskStreet = c.getString(iTaskStreet);
			String taskCity = c.getString(iTaskCity);
			String taskState = c.getString(iTaskState);
			String taskZip = c.getString(iTaskZip);
			
				tempTask = new Task(taskName, taskNote, new Category(taskCat), taskPrior, 
						taskDueDate, taskComplete, taskStreet, taskCity, taskState, taskZip);
			}
		}
		
		return tempTask;
		
	}
	//--------------------------------------------------------------------------------------



}
